using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Nirvana.Common;
using UnityEngine;

namespace Nirvana
{
    /// <summary>
    /// 运行时资源加载控制
    /// </summary>
    public class LoadHelper
    {
        /// <summary>
        /// 加载器
        /// </summary>
        public class Loader : IPoolObject
        {
            /// <summary>
            /// 回调Set
            /// </summary>
            private HashSet<OnLoadComplete> _completes = new HashSet<OnLoadComplete>();

            /// <summary>
            /// 异步资源加载状态管理器
            /// </summary>
            private ResourcesMgr.RequestHandler _request;

            /// <summary>
            /// 资源引用计数器
            /// </summary>
            private int _refCount;

            /// <summary>
            /// 释放资源计时器
            /// </summary>
            private float _releaseTickTime;

            /// <summary>
            /// 资源加载
            /// </summary>
            /// <param name="path"></param>
            /// <param name="func"></param>
            public void Load(string path, OnLoadComplete func)
            {
                // 如果没有加载资源，则开启一个资源加载
                _request ??= ResourcesMgr.Instance.Get(path, OnAssetLoaded);

                // 如果资源已经加载并且加载完成并且返回函数不为空则调用返回函数
                if (_request.IsLoaded())
                {
                    func?.Invoke(_request.GetAsset());
                }
                else
                {
                    _completes.Add(func);
                }

                _refCount++;
            }

            public void UnLoad()
            {
                _refCount--;
            }

            /// <summary>
            /// 检查是否可以释放所有资源
            /// </summary>
            /// <returns></returns>
            public bool Update(float deltaTime)
            {
                if (HasRef())
                {
                    _releaseTickTime = 0;
                    return false;
                }

                _releaseTickTime += deltaTime;

                // 如果3秒后还没有资源引用就清理加载器
                return _releaseTickTime >= 3f;
            }

            public bool HasRef()
            {
                return _refCount != 0;
            }

            /// <summary>
            /// 资源加载成功后，调用所有的OnComplete回调
            /// </summary>
            /// <param name="handler"></param>
            private void OnAssetLoaded(ResourcesMgr.RequestHandler handler)
            {
                foreach (var complete in _completes)
                {
                    complete?.Invoke(handler.GetAsset());
                }
            }

            public void OnGet() { }
            public void OnRelease() { }
        }

        public delegate void OnLoadComplete(object res);

        private static Dictionary<string, Loader> _loaders = new Dictionary<string, Loader>();
        private static Dictionary<string, Loader> _removeLoaders = new Dictionary<string, Loader>();

        /// <summary>
        /// 加载器检查计时器
        /// </summary>
        private static float _deltaTickTime;

        /// <summary>
        /// 加载资源
        /// </summary>
        /// <param name="path"></param>
        /// <param name="callback"></param>
        public static void Load(string path, OnLoadComplete callback)
        {
            if (string.IsNullOrEmpty(path)) return;
            if (!_loaders.TryGetValue(path, out Loader loader))
            {
                if (_removeLoaders.TryGetValue(path, out loader))
                {
                    _removeLoaders.Remove(path);
                }
                else
                {
                    loader = ObjectPool<Loader>.Get();
                }

                _loaders.Add(path, loader);
            }

            loader.Load(path, callback);
        }

        /// <summary>
        /// 卸载资源
        /// </summary>
        /// <param name="path"></param>
        public static void UnLoad(string path)
        {
            if (string.IsNullOrEmpty(path)) return;
            if (!_loaders.TryGetValue(path, out Loader loader)) return;
            loader.UnLoad();
            if (!loader.HasRef())
            {
                _loaders.Remove(path);
                _removeLoaders.Add(path, loader);
            }
        }

        /// <summary>
        /// 每隔1秒检查所有加载器是否还引用资源，如果引用则清理加载器
        /// </summary>
        /// <param name="deltaTime"></param>
        public static void Update(float deltaTime)
        {
            if (_deltaTickTime < 1f) return;
            _deltaTickTime = 0;
            if (_removeLoaders.Count == 0) return;
            List<string> releasedRemoveLoaders = new List<string>();
            foreach (var pair in _removeLoaders.Where(pair => pair.Value.Update(1f)))
            {
                ObjectPool<Loader>.Release(pair.Value);
                releasedRemoveLoaders.Add(pair.Key);
            }

            foreach (var loaderPath in releasedRemoveLoaders)
            {
                _removeLoaders.Remove(loaderPath);
            }

            releasedRemoveLoaders.Clear();
        }
    }
}